////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//
//  Copyright (c) Microsoft Corporation. All rights reserved.
//  Implementation for STM32: Copyright (c) Oberon microsystems, Inc.
//
//  CORTEX-M3 Interrupt Disable Handling 
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <tinyhal.h>

#pragma GCC optimize ("Os")
/*
 *  Usage:
 *  constructor { Release Acquire | Probe } destructor
 *
 *  legal states:     m_state    Primask
 *  WAS_DISABLED         1       1 (disabled)
 *  WAS_ENABLED          0       1 (disabled)
 *  RELEASED             0       0 (enabled)
 */

/*
 *  disabled -> WAS_DISABLED
 *  enabled  -> WAS_ENABLED
 */
SmartPtr_IRQ::SmartPtr_IRQ(void* context)
{
//    m_context = context;
//    Disable();
	__asm volatile("MRS r2, PRIMASK");
	__asm volatile("CPSID i");
	__asm volatile("STR r2, %0" : "=m" (m_state) : );
}

/*
 *  WAS_DISABLED -> disable
 *  WAS_ENABLED  -> enable
 *  RELEASED     -> enable
 */
SmartPtr_IRQ::~SmartPtr_IRQ()
{
//    Restore();
	__asm volatile("LDR r1, %0" : : "m" (m_state));
	__asm volatile("MSR PRIMASK, r1");
}

BOOL SmartPtr_IRQ::WasDisabled()
{
//	return m_state || __get_IPSR() != 0;
	__asm volatile("MRS r1, IPSR");
	__asm volatile("LDR r0, %0" : : "m" (m_state));
	__asm volatile("CBZ r1, L1");
	__asm volatile("MOV r0, #1");
	__asm volatile("L1:");
}

/*
 *  WAS_DISABLED -> WAS_DISABLED
 *  WAS_ENABLED  -> RELEASED
 *  RELEASED     -> RELEASED
 */
void SmartPtr_IRQ::Release()
{
//	Restore();
	__asm volatile("LDR r1, %0" : : "m" (m_state));
	__asm volatile("MSR PRIMASK, r1");
}

/*
 *  WAS_DISABLED -> WAS_DISABLED
 *  WAS_ENABLED  -> WAS_ENABLED
 *  RELEASED     -> WAS_ENABLED
 */
void SmartPtr_IRQ::Acquire()
{
//	__disable_irq();
	__asm volatile("CPSID i");
}

/*
 *  WAS_DISABLED -> WAS_DISABLED
 *  WAS_ENABLED  -> enabled -> WAS_ENABLED
 *  RELEASED     -> RELEASED
 */
void SmartPtr_IRQ::Probe()
{
//	UINT32 m = __get_PRIMASK();
//	__set_PRIMASK(m_state);
//	__set_PRIMASK(m);
	__asm volatile("LDR r1, %0" : : "m" (m_state));
	__asm volatile("MRS r2, PRIMASK");
	__asm volatile("MSR PRIMASK, r1");
	__asm volatile("MSR PRIMASK, r2");
}

// static members
BOOL SmartPtr_IRQ::GetState(void* context)
{
// Also check for interrupt state == 0
//	return (!__get_PRIMASK() && __get_IPSR() == 0);
	__asm volatile("MRS r0, PRIMASK");
	__asm volatile("MRS r1, IPSR");
	__asm volatile("EOR r0, r0, #1");
	__asm volatile("CBZ r1, L2");
	__asm volatile("MOV r0, #0");
	__asm volatile("L2: ");
}

BOOL SmartPtr_IRQ::ForceDisabled(void* context)
{
//	UINT32 m = __get_PRIMASK();
//	__disable_irq();
//	return m ^ 1;
	__asm volatile("MRS r0, PRIMASK");
	__asm volatile("CPSID i");
	__asm volatile("EOR r0, r0, #1");
}

BOOL SmartPtr_IRQ::ForceEnabled(void* context)
{
//	UINT32 m = __get_PRIMASK();
//	__enable_irq();
//	return m ^ 1;
	__asm volatile("MRS r0, PRIMASK");
	__asm volatile("CPSIE i");
	__asm volatile("EOR r0, r0, #1");
}

// private members (not used)
void SmartPtr_IRQ::Disable()
{
//	m_state = __get_PRIMASK();
//	__disable_irq();
	__asm volatile("MRS r1, PRIMASK");
	__asm volatile("CPSID i");
	__asm volatile("STR r1, %0" : "=m" (m_state) : );
}

void SmartPtr_IRQ::Restore()
{
//	__set_PRIMASK(m_state);
	__asm volatile("LDR r1, %0" : : "m" (m_state));
	__asm volatile("MSR PRIMASK, r1");
}
